home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / last.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  9KB  |  378 lines

  1. /* last - display login history            Author: Terrence W. Holm */
  2.  
  3. /* last-    Display the user log-in history.
  4.  *        Last(1) searches backwards through the file of log-in
  5.  *        records (/usr/adm/wtmp), displaying the length of
  6.  *        log-in sessions as requested by the options:
  7.  *
  8.  * Usage:    last [-r] [-count] [-f file] [name] [tty] ...
  9.  *
  10.  *        -r    Search backwards only until the last reboot
  11.  *            record.
  12.  *
  13.  *        -count    Only print out <count> records. Last(1) stops
  14.  *            when either -r or -count is satisfied, or at
  15.  *            the end of the file if neither is given.
  16.  *
  17.  *        -f file    Use "file" instead of "/usr/adm/wtmp".
  18.  *
  19.  *        name    Print records for the user "name".
  20.  *
  21.  *        tty    Print records for the terminal "tty". Actually,
  22.  *            a list of names may be given and all records
  23.  *            that match either the user or tty name are
  24.  *            printed. If no names are given then all records
  25.  *            are displayed.
  26.  *
  27.  *        A sigquit (^\) causes last(1) to display how far it
  28.  *        has gone back in the log-in record file, it then
  29.  *        continues. This is used to check on the progress of
  30.  *        long running searches. A sigint will stop last(1).
  31.  *
  32.  * Author:    Terrence W. Holm    May 1988
  33.  *
  34.  * Revision:
  35.  *        Fred van Kempen, October 1989
  36.  *         -Adapted to MSS.
  37.  *         -Adapted to new utmp database.
  38.  *
  39.  *        Fred van Kempen, December 1989
  40.  *         -Adapted to POSIX (MINIX 1.5)
  41.  *
  42.  *        Fred van Kempen, January 1990
  43.  *         -Final edit for 1.5
  44.  */
  45. #include <sys/types.h>
  46. #include <signal.h>
  47. #include <string.h>
  48. #include <utmp.h>
  49. #include <time.h>
  50. #include <stdlib.h>
  51. #include <stdio.h>
  52.  
  53.  
  54. #define  FALSE    0
  55. #define  TRUE    1
  56.  
  57. #define  BUFFER_SIZE     4096    /* Room for wtmp records */
  58. #define  MAX_WTMP_COUNT  ( BUFFER_SIZE / sizeof(struct utmp) )
  59.  
  60. #define  min( a, b )     ( (a < b) ? a : b )
  61. #define  max( a, b )     ( (a > b) ? a : b )
  62.  
  63.  
  64. typedef struct logout {        /* A logout time record */
  65.   char line[12];        /* The terminal name */
  66.   long time;            /* The logout time */
  67.   struct logout *next;        /* Next in linked list */
  68. } logout;
  69.  
  70.  
  71. static char *Version = "@(#) LAST 1.6 (01/09/90)";
  72.  
  73.  
  74. /* command-line option flags */
  75. char boot_limit = FALSE;    /* stop on latest reboot */
  76. char count_limit = FALSE;    /* stop after print_count */
  77. int print_count;
  78. int arg_count;            /* used to select specific */
  79. char **args;            /* users and ttys */
  80.  
  81. /* global variables */
  82. long boot_time = 0;        /* Zero means no reboot yet */
  83. char *boot_down;        /* "crash" or "down " flag */
  84. logout *first_link = NULL;    /* List of logout times */
  85. int interrupt = FALSE;        /* If sigint or sigquit occurs */
  86.  
  87.  
  88. /* Sigint() and Sigquit() Flag occurrence of an interrupt. */
  89. void Sigint(sig)
  90. int sig;
  91. {
  92.   interrupt = SIGINT;
  93. }
  94.  
  95.  
  96. void Sigquit(sig)
  97. int sig;
  98. {
  99.   interrupt = SIGQUIT;
  100. }
  101.  
  102.  
  103. void usage()
  104. {
  105.   fprintf(stderr, "Usage: last [-r] [-count] [-f file] [name] [tty] ...\n");
  106.   exit(-1);
  107. }
  108.  
  109.  
  110. /* A log-in record format file contains four types of records.
  111.  *
  112.  *  [1] generated on a system reboot:
  113.  *
  114.  *    line="~", name="reboot", host="", time=date()
  115.  *
  116.  *
  117.  *  [2] generated after a shutdown:
  118.  *
  119.  *    line="~", name="shutdown", host="", time=date()
  120.  *
  121.  *
  122.  *  [3] generated on a successful login(1)
  123.  *
  124.  *    line=ttyname(), name=cuserid(), host=, time=date()
  125.  *
  126.  *
  127.  *  [4] generated by init(8) on a logout
  128.  *
  129.  *    line=ttyname(), name="", host="", time=date()
  130.  *
  131.  *
  132.  * Note: This version of last(1) does not recognize the '|' and '}' time
  133.  *     change records. Last(1) pairs up line login's and logout's to
  134.  *     generate four types of output lines:
  135.  *
  136.  *      [1] a system reboot or shutdown
  137.  *
  138.  *       reboot    ~       Mon May 16 14:16
  139.  *       shutdown  ~       Mon May 16 14:15
  140.  *
  141.  *      [2] a login with a matching logout
  142.  *
  143.  *       edwin     tty1    Thu May 26 20:05 - 20:32  (00:27)
  144.  *
  145.  *      [3] a login followed by a reboot or shutdown
  146.  *
  147.  *       root      tty0    Mon May 16 13:57 - crash  (00:19)
  148.  *       root      tty1    Mon May 16 13:45 - down   (00:30)
  149.  *
  150.  *      [4] a login not followed by a logout or reboot
  151.  *
  152.  *       terry     tty0    Thu May 26 21:19   still logged in
  153.  */
  154. Process(wtmp)
  155. struct utmp *wtmp;
  156. {
  157.   logout *link;
  158.   logout *next_link;
  159.  
  160.   /* suppress the job number on an "ftp" line */
  161.   if (!strncmp(wtmp->ut_line, "ftp", 3)) strncpy(wtmp->ut_line, "ftp", 8);
  162.  
  163.   if (!strcmp(wtmp->ut_line, "~")) {
  164.     /* A reboot or shutdown record  */
  165.     if (boot_limit) exit(0);
  166.  
  167.     if (Print_Record(wtmp)) putchar('\n');
  168.     boot_time = wtmp->ut_time;
  169.  
  170.     if (!strcmp(wtmp->ut_name, "reboot"))
  171.         boot_down = "crash";
  172.     else
  173.         boot_down = "down ";
  174.  
  175.     /* remove any logout records */
  176.     for (link = first_link; link != NULL; link = next_link) {
  177.         next_link = link->next;
  178.         free(link);
  179.     }
  180.     first_link = NULL;
  181.   } else if (wtmp->ut_name[0] == '\0') {
  182.     /* A logout record */
  183.     Record_Logout_Time(wtmp);
  184.   } else {
  185.     /* A login record */
  186.     for (link = first_link; link != NULL; link = link->next)
  187.         if (!strncmp(link->line, wtmp->ut_line, 8)) {
  188.             /* found corresponding logout record */
  189.             if (Print_Record(wtmp)) {
  190.                 printf("- %.5s ", ctime(&link->time) + 11);
  191.                 Print_Duration(wtmp->ut_time, link->time);
  192.             }
  193.             /* record login time */
  194.             link->time = wtmp->ut_time;
  195.             return;
  196.         }
  197.     /* could not find a logout record for this login tty */
  198.     if (Print_Record(wtmp))
  199.         if (boot_time == 0)    /* still on */
  200.             printf("  still logged in\n");
  201.         else {        /* system crashed while on */
  202.             printf("- %s ", boot_down);
  203.             Print_Duration(wtmp->ut_time, boot_time);
  204.         }
  205.     Record_Logout_Time(wtmp);    /* Needed in case of 2
  206.                      * consecutive logins  */
  207.   }
  208. }
  209.  
  210.  
  211. /* Print_Record(wtmp) If the record was requested, then print out
  212.  * the user name, terminal, host and time.
  213.  */
  214. Print_Record(wtmp)
  215. struct utmp *wtmp;
  216. {
  217.   int i;
  218.   char print_flag = FALSE;
  219.  
  220.   /* check if we have already printed the requested number of records */
  221.   if (count_limit && print_count == 0) exit(0);
  222.  
  223.   for (i = 0; i < arg_count; ++i)
  224.     if (!strcmp(args[i], wtmp->ut_name) || !strcmp(args[i], wtmp->ut_line))
  225.         print_flag = TRUE;
  226.  
  227.   if (arg_count == 0 || print_flag) {
  228. #ifdef RLOGIN
  229.     printf("%-8.8s  %-8.8s %-16.16s %.16s ",
  230.            wtmp->ut_name, wtmp->ut_line, wtmp->ut_host,
  231.            ctime(&wtmp->ut_time));
  232. #else
  233.     printf("%-8.8s  %-8.8s  %.16s ",
  234.            wtmp->ut_name, wtmp->ut_line, ctime(&wtmp->ut_time));
  235. #endif
  236.     --print_count;
  237.     return(TRUE);
  238.   }
  239.   return(FALSE);
  240. }
  241.  
  242.  
  243. /* Print_Duration(from, to) Calculate and print the days and hh:mm between
  244.  * the log-in and the log-out.
  245.  */
  246. Print_Duration(from, to)
  247. long from;
  248. long to;
  249. {
  250.   long delta, days, hours, minutes;
  251.  
  252.   delta = max(to - from, 0);
  253.   days = delta / (24L * 60L * 60L);
  254.   delta = delta % (24L * 60L * 60L);
  255.   hours = delta / (60L * 60L);
  256.   delta = delta % (60L * 60L);
  257.   minutes = delta / 60L;
  258.  
  259.   if (days > 0)
  260.     printf("(%ld+", days);
  261.   else
  262.     printf(" (");
  263.  
  264.   printf("%02ld:%02ld)\n", hours, minutes);
  265. }
  266.  
  267.  
  268. /* Record_Logout_Time(wtmp) A linked list of "last logout time" is kept.
  269.  * Each element of the list is for one terminal.
  270.  */
  271. Record_Logout_Time(wtmp)
  272. struct utmp *wtmp;
  273. {
  274.   logout *link;
  275.  
  276.   /* see if the terminal is already in the list */
  277.   for (link = first_link; link != NULL; link = link->next)
  278.     if (!strncmp(link->line, wtmp->ut_line, 8)) {
  279.         link->time = wtmp->ut_time;
  280.         return;
  281.     }
  282.   /* allocate a new logout record, for a tty not previously encountered */
  283.   link = (logout *) malloc(sizeof(logout));
  284.   if (link == (logout *) NULL) {
  285.     fprintf(stderr, "last: malloc failure\n");
  286.     exit(1);
  287.   }
  288.   strncpy(link->line, wtmp->ut_line, 8);
  289.   link->time = wtmp->ut_time;
  290.   link->next = first_link;
  291.  
  292.   first_link = link;
  293. }
  294.  
  295.  
  296. main(argc, argv)
  297. int argc;
  298. char *argv[];
  299. {
  300.   char *wtmp_file = WTMP;
  301.   FILE *f;
  302.   long size;            /* Number of wtmp records in the file     */
  303.   long now;            /* time */
  304.   int wtmp_count;        /* How many to read into wtmp_buffer     */
  305.   struct utmp wtmp_buffer[MAX_WTMP_COUNT];
  306.  
  307.   --argc;
  308.   ++argv;
  309.  
  310.   while (argc > 0 && *argv[0] == '-') {
  311.     if (!strcmp(argv[0], "-r"))
  312.         boot_limit = TRUE;
  313.     else if (argc > 1 && !strcmp(argv[0], "-f")) {
  314.         wtmp_file = argv[1];
  315.         --argc;
  316.         ++argv;
  317.     } else if ((print_count = atoi(argv[0] + 1)) > 0)
  318.         count_limit = TRUE;
  319.     else
  320.         usage();
  321.  
  322.     --argc;
  323.     ++argv;
  324.   }
  325.  
  326.   arg_count = argc;
  327.   args = argv;
  328.  
  329.   if ((f = fopen(wtmp_file, "r")) == (FILE *) NULL) {
  330.     perror(wtmp_file);
  331.     exit(1);
  332.   }
  333.   if (fseek(f, 0L, 2) != 0 || (size = ftell(f)) % sizeof(struct utmp) != 0) {
  334.     fprintf(st